package masterjava.common.property;

import masterjava.common.configuration.store.IPeopertiesStore;
import masterjava.common.logging.MasterLogger;

import java.util.Observable;
import java.util.Observer;

/**
 * User: GKislin
 * Date: 20.02.2011
 */
public class Property<T> extends StringConverter<T>{
    protected static final MasterLogger LOGGER = MasterLogger.get(Property.class);
    protected final String key;
    protected final T defValue;
    protected final IPeopertiesStore propStore;
    protected volatile T value;
    protected final PropertyObservable observable = new PropertyObservable();

    public Property(String key, T defValue, Class<T> clazz, IPeopertiesStore propStore) {
        super(clazz);
        this.key = key;
        this.defValue = defValue;
        this.propStore = propStore;
        reInitValue();
    }

    public String getKey() {
        return key;
    }

    public void reInitValue() {
        setValueFromString(getFromStore());
    }

    public void setValueFromString(String newValue) {
        setValue(convert(newValue));
    }

    public void setValue(T newValue) {
        if (newValue != value) {
            T oldValue = value;
            value = newValue;
            observable.fireUpdate(oldValue);
        }
    }

    public void addListener(final IPropertyListener<T> listener) {
        observable.addPropertyListener(listener);
    }

    protected T convert(String property) {
        if (property == null) {
            if (defValue == null) {
                throw LOGGER.getIllegalArgumentException("Property " + key + " coudn't be found");
            }
            return defValue;
        }
        return toValue(property);
    }

    public T get() {
        return value;
    }

    public void set(T newValue) {
        propStore.setProperty(key, toString(newValue));
        setValue(newValue);
    }

    public void setFromString(String newValue) {
        set(convert(newValue));
    }

    public String getFromStore() {
        return propStore.getProperty(key);
    }

    protected class PropertyObservable extends Observable{

        public void fireUpdate(T oldValue){
            setChanged();
            notifyObservers(oldValue);
        }

        public void addPropertyListener(final IPropertyListener<T> listener) {
            addObserver(new Observer() {

                @Override
                @SuppressWarnings("unchecked")
                public void update(Observable propObserv, Object oldValue) {
                    listener.update(Property.this, (T) oldValue);
                }
            });
        }

    }
}
